<?php

namespace App\WeChat\Message;

use App\Model\AutoReplyModel;
use App\Model\BindLogModel;
use App\Model\MpInActivitySubscribeUserModel;
use App\Model\MpInviteCodeModel;
use App\Model\MpInvitedModel;
use App\Model\MpQrDefModel;
use App\Model\MpTextResModel;
use App\Model\MpTplUnsubModel;
use App\Model\UserModel;
use App\WeChat\Message\Activity\InviteMessage;
use App\WeChat\WeChatUtil;
use CURLFile;
use EasySwoole\HttpClient\Exception\InvalidUrl;
use EasySwoole\HttpClient\HttpClient;
use EasySwoole\WeChat\Bean\OfficialAccount\Message\Image;
use EasySwoole\WeChat\Bean\OfficialAccount\Message\News;
use EasySwoole\WeChat\Bean\OfficialAccount\Message\NewsItem;
use EasySwoole\WeChat\Bean\OfficialAccount\Message\Text;
use EasySwoole\WeChat\Bean\OfficialAccount\RequestMsg;


class OnMessageText
{
    public static function handle(RequestMsg $msg)
    {
        $content = strtolower(trim(addslashes($msg->getContent())));
        $pre = (new MpTextResModel())->getTextRes($content);
        //数据库定义的回复
        if ($pre) {
            //链接
            if ($pre['type'] == 0) {
                return self::sendLink($pre);
            } else if ($pre['type'] == 1) {
                //图片
                return self::sendImg($pre['url']);
            } else {
                return null;
            }
        } else {
            if (is_numeric($content)) {
                //领书邀请码
                return self::inviteCodeHandle($msg, $content);
            } else {
                //模板消息 td 退订
                $textStr = self::tdOrDy($msg->getContent(), $msg->getFromUserName());
                if ($textStr) {
                    $text = new Text();
                    $text->setContent($textStr);
                    return $text;
                } else {
                    //默认文字回复
                    $text = new Text();
                    $text->setContent(self::defaultResText());
                    return $text;
                }
            }
        }
    }

    //发送链接
    private static function sendLink($pre)
    {
        $news = new News();
        $newsItem = new NewsItem();
        $newsItem->setTitle($pre['title'] ?? '');
        $newsItem->setDescription($pre['desc'] ?? '');
        $newsItem->setPicUrl('http://brz-mini.oss-cn-beijing.aliyuncs.com/img/20190111113341_5c380e956a4d4.png');
        $newsItem->setUrl($pre['url'] ?? '');
        $news->push($newsItem);
        return $news;
    }

    //发送图片
    private static function sendImg(string $imgUrl)
    {
        $rand = uniqid();
        $imgPath = EASYSWOOLE_ROOT . "/Temp/img_{$rand}.jpg";
        try {
            $cli = new HttpClient($imgUrl);
        } catch (InvalidUrl $e) {
            return null;
        }
        file_put_contents($imgPath, $cli->get()->getBody());
        $img = imagecreatefromjpeg($imgPath);
        $accessToken = (new WeChatUtil())->getAccessToken();
        try {
            $wxRes = (new HttpClient("https://api.weixin.qq.com/cgi-bin/media/upload?access_token={$accessToken}&type=image"))
                ->post([
                    'media' => new CURLFile($imgPath)
                ])
                ->getBody();
            $mediaId = json_decode($wxRes, true)['media_id'];
            //销毁资源
            imagedestroy($img);
            sgo(function () use ($imgPath) {
                unlink($imgPath);
            });
            $img = new Image();
            $img->setMediaId($mediaId);
            return $img;
        } catch (InvalidUrl $e) {
            echo $e->getMessage(), PHP_EOL;
            return null;
        }
    }

    private static function defaultResText(): string
    {
        $model = new AutoReplyModel();
        return $model->getReply(AutoReplyModel::TYPE_SEND_TEXT);
    }

    //td退订/dy重新订阅
    private static function tdOrDy(string $msg, string $openid): ?string
    {
        $cmd = strtolower(trim($msg));
        if ($cmd == 'td') {
            $text = '您已成功退订课程通知【重新订阅请回复DY】';
            sgo(function () use ($openid) {
                (new MpTplUnsubModel())->unsubscribe($openid);
            });
        } else if ($cmd == 'dy') {
            $text = '恭喜！您已成功订阅课程通知';
            sgo(function () use ($openid) {
                (new MpTplUnsubModel())->subscribe($openid);
            });
        } else {
            return null;
        }

        return $text;
    }

    static function inviteCodeHandle(RequestMsg $msg, string $content): Text
    {
        $code = intval($content);
        $openid = $msg->getFromUserName();
        return self::parseCode($code, $openid);
    }

    static function parseCode(int $code, string $openid): Text
    {
        $resText = new Text();
        $util = new WeChatUtil();
        $codeData = (new MpInviteCodeModel())->findByCode($code, ['*']);
        if (!$codeData) {
            //邀请码不存在
            $resText->setContent(self::defaultResText());
            return $resText;
        }
        if ($codeData['openid'] === $openid) {
            $resText->setContent('无法给自己助力！');
            return $resText;
        } else {
            self::bindBToC($codeData['openid'], $openid);
        }
        $qid = $codeData['qid'];
        //3.二维码数据
        $qrDef = (new MpQrDefModel())->findById($qid);
        $qrDefName = $qrDef['name'];
        //4.当前用户昵称  发起人用户昵称
        $nickname = $util->getNickname($openid);
        $nicknameOfA = (new UserModel())->getColumnByUid($codeData['uid'], ['nickname'])['nickname'] ?? '';
        //5.活动前关注公众号的用户无法为好友助力
        $isNewSub = (new MpInActivitySubscribeUserModel())->isNewSubscribe($openid);
        if (!$isNewSub) {
            $resText->setContent(InviteMessage::bIsOldUserMessage());
            echo "老用户了！\n";
            return $resText;
        }
        //6.邀请码的任务如果已经完成则提示用户无法助力
        if ($codeData['is_complete'] == 1) {
            $resText->setContent(InviteMessage::onACompleteButBSendCodeMessage($nicknameOfA, $qrDefName));
            echo "助力完成！\n";
            return $resText;
        }
        //7.开始助力
        $invited = (new MpInvitedModel())->findByOpenid($openid, ['*']);
        if ($invited) {
            echo "重复助力！\n";
            //重复助力
            $resText->setContent(InviteMessage::onBRepeatActionMessage($nicknameOfA, $qrDefName));
        } else {
            //记录用户助力
            sgo(function () use ($openid, $code) {
                (new MpInvitedModel())->insert(['openid' => $openid, 'code' => $code, 'add_time' => time(),]);
            });
            //增加A的助力人数并判断是否助力完成
            $codeModel = new MpInviteCodeModel();
            $currCount = $codeModel->incrInvitedCountByCode($code);
            $needCount = (new MpQrDefModel())->findById($qid)['need'];
            echo "curr:$currCount,need:$needCount\n";
            //助力成功
            $resText->setContent(InviteMessage::onInviteSuccessForBMessage($nicknameOfA, $qrDefName));
            $openidForA = (new UserModel())->getColumnByUid($codeData['uid'], ['mp_openid'])['mp_openid'] ?? '';
            if ($currCount >= $needCount) {
                //助力完成
                $codeModel->setIsComplete($code);
                sgo(function () use ($util, $nickname, $codeData, $needCount, $currCount, $qid, $openidForA, $code, $qrDef) {
                    $def = (new MpQrDefModel())->findById($qid);
                    $defName = $def['name'];
                    $forAMsg = InviteMessage::onATaskCompleteMessage($nickname, $needCount, $currCount, $defName, $code, $qrDef['type']);
                    $util->sendTextMsg($openidForA, $forAMsg, $util->getAccessToken());
                });
            } else {
                sgo(function () use ($util, $nickname, $codeData, $needCount, $currCount, $openidForA, $qrDefName) {
                    $forAMsg = InviteMessage::onInviteSuccessForAMessage($nickname, $needCount, $currCount, $qrDefName);
                    $util->sendTextMsg($openidForA, $forAMsg, $util->getAccessToken());
                });
            }
        }

        return $resText;
    }

    //B到C的绑定
    static function bindBToC(string $fromOpenid, string $toOpenid): void
    {
        sgo(function () use ($fromOpenid, $toOpenid) {
            $userModel = new UserModel();
            $toUser = $userModel->getColumnByOpenid($toOpenid, ['id', 'consultant_id']);
            if ($toUser && $toUser['consultant_id'] == 0) {
                $toUid = $toUser['id'];
                $fromUser = $userModel->getColumnByOpenid($fromOpenid, ['id', 'consultant_id']);
                if ($fromUser) {
                    $fromUid = $fromUser['id'];
                    if ($fromUser['consultant_id'] == 0) {
                        $mode = 'a_to_b';
                        $topConsId = $fromUid;
                        $update = [
                            'consultant_id' => $fromUid,
                            'pyramid_level' => 1,
                            'top_cons_id' => $topConsId,
                        ];
                    } else {
                        $mode = 'b_to_c';
                        $topConsId = $fromUser['consultant_id'];
                        $update = [
                            'consultant_id' => $fromUid,
                            'pyramid_level' => 2,
                            'top_cons_id' => $topConsId,
                        ];
                    }
                    $userModel->updateById($toUid, $update);
                    self::addBindLog($fromUid, $toUid, $mode, $topConsId);
                }
            }
        });
    }

    static function addBindLog(int $fromUid, int $toUid, string $mode, int $topConsId)
    {
        $data = [
            'from_uid' => $fromUid,
            'to_uid' => $toUid,
            'mode' => $mode,
            'action' => 'invited_code',
            'top_consultant_id' => $topConsId,
            'add_time' => time()
        ];
        sgo(function () use ($data) {
            (new BindLogModel())->insert($data);
        });
    }
}
